package com.sugon.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.sugon.dao.SparePartDao;
import com.sugon.dao.SparePartInDao;
import com.sugon.entity.*;
import com.sugon.modules.sparepart.consts.SparePartResource;
import com.sugon.modules.sparepart.model.vo.SparePartRequDetailVO;
import com.sugon.modules.sparepart.service.ISparepartNeedsPlanManager;
import com.sugon.modules.sys.service.INoticeManager;
import com.sugon.service.*;
import com.sugon.utils.Constant;
import com.sugon.utils.RRException;
import com.sugon.utils.ShiroUtils;
import com.sugon.utils.excel.ExcelExport;
import com.sugon.utils.excel.ExcelImport;
import org.apache.shiro.util.Assert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;

import static com.sugon.utils.ShiroUtils.getUserId;
import static com.sugon.utils.ShiroUtils.getUserName;

/**
 * 入库记录Service实现类
 *
 * @author sugon
 * @date 2019-07-12 08:50:22
 */
@Service("sparePartInService")
public class SparePartInServiceImpl implements SparePartInService {
    @Autowired
    private SparePartInDao sparePartInDao;
    @Autowired
    private SparePartDao sparePartDao;
    @Autowired
    private SpareStorePosService spareStorePosService;
    @Autowired
    private ISparepartNeedsPlanManager sparepartNeedsPlanManager;
    @Autowired
    private SparePartRequDetailService sparePartRequDetailService;
    @Autowired
    private SparePartService sparePartService;
    @Resource
    private SparePartTransactionRecordService sparePartTransactionService;
    @Resource
    private INoticeManager noticeManager;

    @Override
    public Integer statTotalNum(String posId, String month) {
        Integer totalNum = sparePartInDao.statTotalNum(posId, month);
        return totalNum == null ? 0 : totalNum;
    }

    @Override
    public SparePartInEntity queryObject(String id) {
        return sparePartInDao.queryObject(id);
    }

    @Override
    public List<SparePartInEntity> queryList(Map<String, Object> map) {
        return sparePartInDao.queryList(map);
    }

    @Override
    public int queryTotal(Map<String, Object> map) {
        return sparePartInDao.queryTotal(map);
    }

    @Override
    public int save(SparePartInEntity sparePartIn) {
        // 保存信息
        sparePartIn.setId(RandomUtil.randomString(32));
        sparePartIn.setCreateUser(getUserId());
        sparePartIn.setCreateDate(DateUtil.date());
        sparePartIn.setUpdateDate(sparePartIn.getCreateDate());
        sparePartIn.setUpdateUser(sparePartIn.getCreateUser());
        return sparePartInDao.save(sparePartIn);
    }

    @Override
    public synchronized String generateUniqueCode(Object object) {
        // 声明当天的入库编码前缀
        String codePrefix = Constant.SPARE_IN + "-" + DateUtil.format(DateUtil.date(), "yyyyMMdd") + "-";
        String spareUniqueCode = (String) object;
        if (StrUtil.isEmpty(spareUniqueCode)) {
            // 查询当前最新的入库编码
            spareUniqueCode = sparePartInDao.getLastestPartCode(codePrefix);
        }
        // 生成新的唯一编码
        spareUniqueCode = com.sugon.modules.utils.StrUtil.increase(spareUniqueCode, codePrefix, 4, 1);
        // 确保最新生成备件编码不重复
        SparePartInEntity sparePartInRecord = queryByCode(spareUniqueCode);
        if (sparePartInRecord == null) {
            return spareUniqueCode;
        }
        return generateUniqueCode(spareUniqueCode);
    }

    @Override
    public SparePartInEntity queryByCode(String sparePartInCode) {
        Map<String, Object> param = new HashMap<>(1);
        param.put("inCode", sparePartInCode);
        List<SparePartInEntity> sparePartInList = sparePartInDao.queryList(param);
        return CollectionUtil.isNotEmpty(sparePartInList) ? sparePartInList.get(0) : null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int inbound(SparePartInEntity sparePartIn) {
        sparePartIn.setInCode(generateUniqueCode());
        sparePartIn.setInDate(DateUtil.date());
        sparePartIn.setOperation(getUserId());
        sparePartIn.setOperationName(ShiroUtils.getUserEntity().getNickName());
        // 1、生成备件入库记录
        String partCode = sparePartIn.getPartCode();
        if (StrUtil.isNotEmpty(partCode)) {
            SparePartEntity sparePart = sparePartService.queryByCode(partCode);
            if (sparePart != null) {
                sparePartIn.setPartUnit(sparePart.getUnit());
                BigDecimal price = sparePart.getPrice();
                if (price != null) {
                    sparePartIn.setPartPrice(price.toString());
                }
                sparePartIn.setSpareId(sparePart.getId());
                // 如果备件未设置备件分类，需要推送企业微信给 袁西，张丽华
                if (StrUtil.isEmpty(sparePart.getInstallPosition())) {
                    noticeManager.pushSpCatUnSetNotice(sparePart);
                }
            }
        }
        /*
            校验备件入库信息中查询库位是否存在
                如果存在，不做处理
                如果不存在，则根据仓库ID、备件编码和库位编码查询并设置
         */
        if (StrUtil.isEmpty(sparePartIn.getCargoLocation())) {
            SpareStorePosEntity spareStorePos = spareStorePosService.queryOrCreateIfNotExists(sparePartIn.getInStoreId(), sparePartIn.getCargoLocationName(), sparePartIn.getPartCode(), sparePartIn.getSpareId());
            sparePartIn.setCargoLocation(spareStorePos.getId());
        }

        int rows = save(sparePartIn);
        if (rows > 0) {
            /*
                处理两个逻辑：
                1、备件库位库存数、备件库存数的增减
                2、如果是需求计划入库，则需要修改在途和入库数
                以及向相关责任人发送入库消息
             */
            // 1、生成备件入库事务明细。生成成功后，实时更新库位库存数和备件库存数
            boolean generateFlag = sparePartTransactionService.generateInTransaction(sparePartIn);
            if (generateFlag) {
                // 实时更新仓库库位库存数
                spareStorePosService.realtimeUpdateStorePosStock(sparePartIn.getCargoLocation());
                // 实时更新备件库存数
                sparePartDao.realtimeUpdateStock(sparePartIn.getPartCode());
            }
            /*
                2、校验下来源是否是需求计划
                1、如果是的话需要，修改需求中的在途和入库数，并更新备件的在途数
                2、向该备件需求明细的编制用户发送入库通知
                3、生成备件到货周期记录
             */
            if (SparePartResource.BJXQ.equals(sparePartIn.getResources())) {
                // 修改需求中的在途和入库数，并更新备件的在途数
                sparepartNeedsPlanManager.reduceTransitNum(sparePartIn.getPartNeedsItemId(), sparePartIn.getInNum());
                // 向该备件需求明细的编制用户发送入库通知
                String partNeedsItemId = sparePartIn.getPartNeedsItemId();
                Assert.notNull(partNeedsItemId, "需求备件入库时，必须关联需求明细！");
                SparePartRequDetailVO partNeedsItem = sparePartRequDetailService.queryObject(partNeedsItemId);
                if (partNeedsItem != null) {
                    // 推送备件到货通知
                    noticeManager.pushDeliveryNotice(partNeedsItem, getUserName(), sparePartIn.getInNum());
                    // 应客户要求，不管一个备件需求计划明细到货多少次，只记录第一次的，用作后续查询用
                    if (partNeedsItem.getActualArriveTime() == null) {
                        partNeedsItem.setActualArriveTime(DateUtil.beginOfDay(DateUtil.date()));
                        sparePartRequDetailService.update(partNeedsItem);
                    }
                    // 记录备件到货周期记录
                    if (partNeedsItem.getOrderGenerateTime() != null) {
                        SparePartDeliveryRecord deliveryRecord = new SparePartDeliveryRecord();
                        deliveryRecord.setSpareId(sparePartIn.getSpareId());
                        deliveryRecord.setOrderGenerateTime(partNeedsItem.getOrderGenerateTime());
                        deliveryRecord.setTheoryArriveTime(partNeedsItem.getArriveTime());
                        deliveryRecord.setCreateTime(DateUtil.date());
                        deliveryRecord.setActualArriveTime(DateUtil.date());
                        deliveryRecord.setActualDeliveryCycle(DateUtil.betweenDay(deliveryRecord.getOrderGenerateTime(), deliveryRecord.getActualArriveTime(), true));
                        deliveryRecord.setPurchaseQuantity(partNeedsItem.getDemandNum());
                        deliveryRecord.setArriveQuantity(sparePartIn.getInNum());
                        deliveryRecord.setNeedsItemId(partNeedsItem.getId());
                        deliveryRecord.setStockInRecordId(sparePartIn.getId());
                        deliveryRecord.setId(RandomUtil.randomString(32));
                        sparePartInDao.saveDeliveryRecord(deliveryRecord);
                    }
                }
            }
        }
        return rows;
    }

    @Override
    public int update(SparePartInEntity sparePartIn) {
        sparePartIn.setUpdateUser(getUserId());
        sparePartIn.setUpdateDate(new Date());
        return sparePartInDao.update(sparePartIn);
    }

    @Override
    public int delete(String id) {
        return sparePartInDao.delete(id);
    }

    @Override
    public int deleteBatch(String[] ids) {
        return sparePartInDao.deleteBatch(ids);
    }

    @Override
    public int importE(MultipartFile file) throws Exception {
        String err = "";
        if (file.isEmpty()) {
            throw new RRException("上传文件不能为空");
        }
        List list = ExcelImport.getExcelData(file);
        if (list != null && list.size() != 0) {
            String[] header = new String[]{"来源", "入库单号", "入库日期", "使用单位", "入库仓库", "货位", "系统编号", "名称", "规格", "单位", "单价",
                    "入库数量", "使用设备码", "使用设备", "使用工序", "操作人", "审核人", "审核状态", "审核时间", "备注", "添加时间"};
            String[] data = (String[]) list.get(0);
            int j = 0;
            for (String d : data) {
                if (header[j].equals(d.trim())) {
                    j++;
                }
            }
            if (j < header.length) {
                err = "找不到\"" + header[j] + "\"这一列";
            }
            if (err.equals("")) {
                sparePartInDao.delete(null);
                for (int i = 1; i < list.size(); i++) {
                    SparePartInEntity sparePartInEntity = new SparePartInEntity();
                    sparePartInEntity.setValues((String[]) list.get(i));
                    sparePartInEntity.setId(RandomUtil.randomString(32));
                    sparePartInEntity.setCreateUser(getUserId());
                    sparePartInEntity.setCreateDate(new Date());
                    sparePartInDao.save(sparePartInEntity);
                }
            }
        }
        return 0;
    }

    @Override
    public void export(Map<String, Object> params, HttpServletResponse response) {
        List<SparePartInEntity> sparePartInEntityList = sparePartInDao.queryList(params);
        ExcelExport ee = new ExcelExport("备件入库记录");
        String[] header = new String[]{"来源", "入库单号", "入库日期", "使用单位", "入库仓库", "货位", "备件编码", "ERP编码", "名称", "规格", "单位", "单价",
                "入库数量", "计划编码", "使用设备码", "使用设备", "使用工序", "操作人", "审核人", "审核状态", "审核时间", "备注", "添加时间"};
        List<Map<String, Object>> list = new ArrayList<>();
        if (sparePartInEntityList != null && sparePartInEntityList.size() != 0) {
            for (SparePartInEntity sp : sparePartInEntityList) {
                LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                map.put("resources", sp.getResources());
                map.put("inCode", sp.getInCode());
                map.put("inDate", sp.getInDate());
                map.put("useUnit", sp.getUseUnit());
                map.put("intStore", sp.getIntStore());
                map.put("cargoLocation", sp.getCargoLocation());
                map.put("partCode", sp.getPartCode());
                // ERP编码
                map.put("erpCode", sp.getErpCode());
                map.put("name", sp.getName());
                map.put("spec", sp.getSpec());
                map.put("partUnit", sp.getPartUnit());
                map.put("partPrice", sp.getPartPrice());
                map.put("inNum", sp.getInNum());
                // 计划编码
                map.put("planCode", sp.getBusinessCode());
                map.put("useDevCode", sp.getUseDevCode());
                map.put("useDevName", sp.getUseDevName());
                map.put("procUse", sp.getProcUse());
                map.put("operation", sp.getOperationName());
                map.put("remark", sp.getRemark());
                map.put("createDate", sp.getCreateDate());
                list.add(map);
            }
        }
        ee.addSheetByMap("备件入库记录", list, header);
        ee.export(response);
    }

    @Override
    public int save2(SparePartInEntity sparePartInEntity) {
        sparePartInEntity.setId(RandomUtil.randomString(32));
        return sparePartInDao.save(sparePartInEntity);
    }

}
